﻿using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Ewk.Math.ComputationTypes.UnitTests
{
    [TestClass]
    public class ComputableDoubleUnitTests : ComputableUnitTestsBase<double>
    {
        [TestMethod]
        public void ComputableDouble_can_be_added_to_another_ComputableDouble()
        {
            var a = Computable<double>.Factory.Create(12);
            var b = Computable<double>.Factory.Create(3);

            var c = a + b;

            Assert.AreEqual(15.0, c.Value);
        }

        [TestMethod]
        public void ComputableDouble_can_be_increased_using_the_increment_operator()
        {
            var a = Computable<double>.Factory.Create(12);

            a++;

            Assert.AreEqual(13.0, a.Value);
        }

        [TestMethod]
        public void ComputableDouble_can_be_subtracted_from_another_ComputableDouble()
        {
            var a = Computable<double>.Factory.Create(12);
            var b = Computable<double>.Factory.Create(3);

            var c = a - b;

            Assert.AreEqual(9.0, c.Value);
        }

        [TestMethod]
        public void ComputableDouble_can_be_decreased_using_the_decrement_operator()
        {
            var a = Computable<double>.Factory.Create(12);

            a--;

            Assert.AreEqual(11.0, a.Value);
        }

        [TestMethod]
        public void ComputableDouble_can_be_multiplied_by_another_ComputableDouble()
        {
            var a = Computable<double>.Factory.Create(12);
            var b = Computable<double>.Factory.Create(3);

            var c = a*b;

            Assert.AreEqual(36.0, c.Value);
        }

        [TestMethod]
        public void ComputableDouble_can_be_divided_by_another_ComputableDouble()
        {
            var a = Computable<double>.Factory.Create(12);
            var b = Computable<double>.Factory.Create(3);

            var c = a/b;

            Assert.AreEqual(4.0, c.Value);
        }

        [TestMethod]
        public void ComputableDouble_Zero_instance_is_mutated_on_computation_on_the_instance()
        {
            var zero = Computable<double>.Factory.Zero;
            var one = Computable<double>.Factory.One;
            zero.Subtract(one);

            Assert.AreEqual(-1.0, zero.Value);
        }

        #region Overloaded operators

        #region Equals

        [TestMethod]
        public void Computable_overloaded_operator_equal_returns_true_when_two_instances_of_One_Computable_are_compared()
        {
            var value1 = Computable<double>.Factory.One;
            var value2 = Computable<double>.Factory.One;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsTrue(value1 == value2);
        }

        [TestMethod]
        public void Computable_overloaded_operator_equal_returns_true_when_two_instances_of_Zero_Computable_are_compared
            ()
        {
            var value1 = Computable<double>.Factory.Zero;
            var value2 = Computable<double>.Factory.Zero;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsTrue(value1 == value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_equal_returns_false_when_an_instance_of_One_Computable_is_compared_to_instance_of_Zero_Computable
            ()
        {
            Assert.IsFalse(Computable<double>.Factory.One == Computable<double>.Factory.Zero);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_equal_returns_false_when_instance_of_Zero_Computable_is_compared_to_an_instance_of_One_Computable
            ()
        {
            Assert.IsFalse(Computable<double>.Factory.Zero == Computable<double>.Factory.One);
        }

        #endregion

        #region Not Equals

        [TestMethod]
        public void
            Computable_overloaded_operator_not_equal_returns_false_when_two_instances_of_One_Computable_are_compared()
        {
            var value1 = Computable<double>.Factory.One;
            var value2 = Computable<double>.Factory.One;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsFalse(value1 != value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_not_equal_returns_false_when_two_instances_of_Zero_Computable_are_compared()
        {
            var value1 = Computable<double>.Factory.Zero;
            var value2 = Computable<double>.Factory.Zero;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsFalse(value1 != value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_not_equal_returns_true_when_an_instance_of_One_Computable_is_compared_to_instance_of_Zero_Computable
            ()
        {
            Assert.IsTrue(Computable<double>.Factory.One != Computable<double>.Factory.Zero);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_not_equal_returns_true_when_instance_of_Zero_Computable_is_compared_to_an_instance_of_One_Computable
            ()
        {
            Assert.IsTrue(Computable<double>.Factory.Zero != Computable<double>.Factory.One);
        }

        #endregion

        #region Smaller Than

        [TestMethod]
        public void
            Computable_overloaded_operator_smaller_than_returns_false_when_two_instances_of_One_Computable_are_compared()
        {
            var value1 = Computable<double>.Factory.One;
            var value2 = Computable<double>.Factory.One;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsFalse(value1 < value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_smaller_than_returns_false_when_two_instances_of_Zero_Computable_are_compared
            ()
        {
            var value1 = Computable<double>.Factory.Zero;
            var value2 = Computable<double>.Factory.Zero;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsFalse(value1 < value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_smaller_than_returns_false_when_an_instance_of_One_Computable_is_compared_to_instance_of_Zero_Computable
            ()
        {
            Assert.IsFalse(Computable<double>.Factory.One < Computable<double>.Factory.Zero);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_smaller_than_returns_true_when_instance_of_Zero_Computable_is_compared_to_an_instance_of_One_Computable
            ()
        {
            Assert.IsTrue(Computable<double>.Factory.Zero < Computable<double>.Factory.One);
        }

        #endregion

        #region Smaller Than Or Equal

        [TestMethod]
        public void
            Computable_overloaded_operator_smaller_than_or_equal_returns_true_when_two_instances_of_One_Computable_are_compared
            ()
        {
            var value1 = Computable<double>.Factory.One;
            var value2 = Computable<double>.Factory.One;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsTrue(value1 <= value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_smaller_than_or_equal_returns_true_when_two_instances_of_Zero_Computable_are_compared
            ()
        {
            var value1 = Computable<double>.Factory.Zero;
            var value2 = Computable<double>.Factory.Zero;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsTrue(value1 <= value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_smaller_than_or_equal_returns_false_when_an_instance_of_One_Computable_is_compared_to_instance_of_Zero_Computable
            ()
        {
            Assert.IsFalse(Computable<double>.Factory.One <= Computable<double>.Factory.Zero);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_smaller_than_or_equal_returns_true_when_instance_of_Zero_Computable_is_compared_to_an_instance_of_One_Computable
            ()
        {
            Assert.IsTrue(Computable<double>.Factory.Zero <= Computable<double>.Factory.One);
        }

        #endregion

        #region Greater Than

        [TestMethod]
        public void
            Computable_overloaded_operator_greater_than_returns_false_when_two_instances_of_One_Computable_are_compared()
        {
            var value1 = Computable<double>.Factory.One;
            var value2 = Computable<double>.Factory.One;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsFalse(value1 > value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_greater_than_returns_false_when_two_instances_of_Zero_Computable_are_compared
            ()
        {
            var value1 = Computable<double>.Factory.Zero;
            var value2 = Computable<double>.Factory.Zero;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsFalse(value1 > value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_greater_than_returns_true_when_an_instance_of_One_Computable_is_compared_to_instance_of_Zero_Computable
            ()
        {
            Assert.IsTrue(Computable<double>.Factory.One > Computable<double>.Factory.Zero);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_greater_than_returns_false_when_instance_of_Zero_Computable_is_compared_to_an_instance_of_One_Computable
            ()
        {
            Assert.IsFalse(Computable<double>.Factory.Zero > Computable<double>.Factory.One);
        }

        #endregion

        #region Greater Than Or Equal

        [TestMethod]
        public void
            Computable_overloaded_operator_greater_than_or_equal_returns_true_when_two_instances_of_One_Computable_are_compared
            ()
        {
            var value1 = Computable<double>.Factory.One;
            var value2 = Computable<double>.Factory.One;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsTrue(value1 >= value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_greater_than_or_equal_returns_true_when_two_instances_of_Zero_Computable_are_compared
            ()
        {
            var value1 = Computable<double>.Factory.Zero;
            var value2 = Computable<double>.Factory.Zero;

            Assert.IsFalse(ReferenceEquals(value1, value2));
            Assert.IsTrue(value1 >= value2);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_greater_than_or_equal_returns_true_when_an_instance_of_One_Computable_is_compared_to_instance_of_Zero_Computable
            ()
        {
            Assert.IsTrue(Computable<double>.Factory.One >= Computable<double>.Factory.Zero);
        }

        [TestMethod]
        public void
            Computable_overloaded_operator_greater_than_or_equal_returns_false_when_instance_of_Zero_Computable_is_compared_to_an_instance_of_One_Computable
            ()
        {
            Assert.IsFalse(Computable<double>.Factory.Zero >= Computable<double>.Factory.One);
        }

        #endregion

        #endregion
    }
}